package com.patentbackend.patentmanage.service.lmpl;

import com.patentbackend.patentmanage.dto.request.RegisterRequest;
import com.patentbackend.patentmanage.entity.Role;
import com.patentbackend.patentmanage.entity.User;
import com.patentbackend.patentmanage.repository.RoleRepository;
import com.patentbackend.patentmanage.repository.UserRepository;
import com.patentbackend.patentmanage.security.UserDetailsImpl;
import com.patentbackend.patentmanage.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RoleRepository roleRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public User registerUser(RegisterRequest signUpRequest) {
        User user = User.builder()
                .username(signUpRequest.getUsername())
                .email(signUpRequest.getEmail())
                .password(passwordEncoder.encode(signUpRequest.getPassword()))
                .employeeId(signUpRequest.getEmployeeId())
                .realName(signUpRequest.getName())
                .organization(signUpRequest.getOrganization())
                .department(signUpRequest.getDepartment())
                .phone(signUpRequest.getPhone())
                .status(0) // 0: 待审核
                .build();

        Set<String> strRoles = signUpRequest.getRoles();
        Set<Role> roles = new HashSet<>();

        if (strRoles == null) {
            Role userRole = roleRepository.findByName("ROLE_USER")
                    .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
            roles.add(userRole);
        } else {
            strRoles.forEach(role -> {
                switch (role) {
                    case "admin":
                        Role adminRole = roleRepository.findByName("ROLE_ADMIN")
                                .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                        roles.add(adminRole);
                        break;
                    case "internal":
                        Role modRole = roleRepository.findByName("ROLE_INTERNAL")
                                .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                        roles.add(modRole);
                        break;
                    default:
                        Role userRole = roleRepository.findByName("ROLE_USER")
                                .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                        roles.add(userRole);
                }
            });
        }

        user.setRoles((List<Role>) roles);
        return userRepository.save(user);
    }

    @Override
    public Optional<User> findByUsername(String username) {
        return userRepository.findByUsername(username);
    }

    @Override
    public Boolean existsByUsername(String username) {
        return userRepository.existsByUsername(username);
    }

    @Override
    public Boolean existsByEmployeeId(String employeeId) {
        return userRepository.existsByEmployeeId(employeeId);
    }

    @Override
    public Boolean existsByEmail(String email) {
        return userRepository.existsByEmail(email);
    }

    @Override
    public User getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
        return userRepository.findById(userDetails.getId())
                .orElseThrow(() -> new RuntimeException("User not found"));
    }

    @Override
    public Page<User> findAll(Pageable pageable) {
        return userRepository.findAll(pageable);
    }

    @Override
    public Optional<User> findById(Long id) {
        return userRepository.findById(id);
    }

    @Override
    public User save(User user) {
        return null;
    }

    @Override
    public boolean existsById(Long id) {
        return userRepository.existsById(id);
    }

    @Override
    public User updateUser(Long id, RegisterRequest userDto) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("User not found with id: " + id));

        if (userDto.getUsername() != null) user.setUsername(userDto.getUsername());
        if (userDto.getEmail() != null) user.setEmail(userDto.getEmail());
        if (userDto.getPassword() != null) user.setPassword(passwordEncoder.encode(userDto.getPassword()));
        if (userDto.getEmployeeId() != null) user.setEmployeeId(userDto.getEmployeeId());
        if (userDto.getName() != null) user.setRealName(userDto.getName());
        if (userDto.getOrganization() != null) user.setOrganization(userDto.getOrganization());
        if (userDto.getDepartment() != null) user.setDepartment(userDto.getDepartment());
        if (userDto.getPhone() != null) user.setPhone(userDto.getPhone());

        return userRepository.save(user);
    }

    @Override
    public User verifyUser(Long id, boolean verified, List<String> roles) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("User not found with id: " + id));

        user.setStatus(verified ? 1 : 2); // 1: 已通过, 2: 已拒绝

        if (roles != null && !roles.isEmpty()) {
            Set<Role> userRoles = new HashSet<>();
            roles.forEach(role -> {
                Role userRole = roleRepository.findByName("ROLE_" + role.toUpperCase())
                        .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                userRoles.add(userRole);
            });
            user.setRoles((List<Role>) userRoles);
        }

        return userRepository.save(user);
    }

    @Override
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}